
from ...service.mongo_bill_service import MongoBillFilter
from server.pao_python.pao.service.data.mongo_db import MongoService, MongoFilter, C, N, F, as_date
from ...service.buss_pub.bill_manage import BillManageService, OperationType, TypeId, Status
from ...service.common import insert_data, find_data, update_data, delete_data, get_condition, get_info, get_current_user_id
from ...pao_python.pao.service.security.security_utility import get_current_account_id
from ...pao_python.pao.service.security.security_service import RoleService
import hashlib
import re
import datetime
import uuid
import requests
import math
import base64
import pandas as pd
from ...pao_python.pao.data import process_db, dataframe_to_list, DataProcess, DataList
from ...service.constant import FollowCollectionObject, FollowCollectionType
from ...service.buss_mis.operation_record import OperationRecordObject, OperationRecordType, OperationRecordService
# -*- coding: utf-8 -*-


class ServiceFollowCollectionObject():
    '''服务关注收藏对象'''

    def __init__(self, user_id, business_id, s_object, s_type):
        '''构造函数'''
        # 操作人id
        self.user_id = user_id
        # 业务表id
        self.business_id = business_id
        # 类型
        self.object = s_object
        # 类型
        self.type = s_type

    def to_dict(self):
        return self.__dict__


"""
服务关注收藏管理函数
"""


class ServiceFollowCollectionService(MongoService):
    """ 服务关注收藏管理 """

    def __init__(self, db_addr, db_port, db_name, db_user, db_pwd, inital_password, session):
        DataProcess.__init__(self, db_addr, db_port, db_name, db_user, db_pwd)
        # self.db_name = db_name
        self.inital_password = inital_password
        self.session = session
        self.bill_manage_service = BillManageService(
            db_addr, db_port, db_name, db_user, db_pwd, inital_password, session
        )
        self.OperationRecordService = OperationRecordService(
            db_addr, db_port, db_name, db_user, db_pwd, inital_password, session)

    def get_service_follow_collection_follow_list(self, condition, page, count):
        """获取机构关注列表

        Arguments:
            condition   {dict}      条件
            page        {number}    页码
            count       {number}    条数
        """
        keys = ["id", "business_id", "user_id"]
        values = self.get_value(condition, keys)
        _filter = MongoBillFilter()
        if 'is_own' in condition.keys():
            user_id = get_current_user_id(self.session)
            _filter.match_bill((C('user_id') == user_id))
        _filter.match_bill((C("id") == values["id"])
                           & (C("type") == FollowCollectionType.follow)
                           & (C("business_id") == values["business_id"])
                           & (C("user_id") == values["user_id"]))\
            .lookup_bill('PT_User', 'user_id', 'id', 'user')\
            .lookup_bill('PT_User', 'business_id', 'id', 'obj')\
            .sort({'create_date': -1})\
            .project({"_id": 0, "user._id": 0, "obj._id": 0})
        res = self.page_query(
            _filter, "PT_Service_Follow_Collection", page, count)
        return res

    def get_service_follow_collection_list(self, condition, page, count):
        """获取关注、收藏列表

        Arguments:
            condition   {dict}      条件
            page        {number}    页码
            count       {number}    条数
        """
        def convertDegreesToRadians(degrees):
            return degrees * math.pi / 180

        def coverGpsToBaiduLatLon(lat, lon):
            baidu_map_url = 'http://api.map.baidu.com/ag/coord/convert?from=0&to=4&x=%f&y=%f'

            data_req = requests.get((baidu_map_url % (lon, lat)))
            new_pos = data_req.json()
            if 'error' in new_pos.keys() and new_pos['error'] == 0:
                lon = float(base64.b64decode(
                    new_pos['x']).decode("utf-8"))
                lat = float(base64.b64decode(
                    new_pos['y']).decode("utf-8"))
                return lat, lon

        keys = ["id", "object", "type", "business_id",
                "user_id", 'name', 'lat', 'lon']
        values = self.get_value(condition, keys)
        _filter = MongoBillFilter()
        if 'is_own' in condition.keys():
            user_id = get_current_user_id(self.session)
            _filter.match_bill((C('user_id') == user_id))
        _filter.match_bill((C("id") == values["id"])
                           & (C("type") == values["type"])
                           & (C("object") == values["object"])
                           & (C("business_id") == values["business_id"])
                           & (C("user_id") == values["user_id"]))\
            .lookup_bill('PT_User', 'user_id', 'id', 'user')
        if 'object' in condition.keys() and (condition['object'] == FollowCollectionObject.welfare or condition['object'] == FollowCollectionObject.community or condition['object'] == FollowCollectionObject.provider):
            _filter.lookup_bill('PT_User', 'business_id', 'id', 'obj_list')\
                .add_fields({'obj': self.ao.array_elemat("$obj_list", 0)})\
                .lookup_bill('PT_Service_Follow_Collection', 'obj_list.id', 'business_id', 'follow_info')\
                .add_fields({'follow_count': self.ao.size('$follow_info'), })\
                .lookup_bill('PT_Administration_Division', 'obj_list.admin_area_id', 'id', 'area')\
                .add_fields({'area': '$area.name'})\
                .match_bill((C("obj_list.name").like(values["name"])))\
                .project({'area._id': 0, 'obj_list._id': 0, 'follow_info._id': 0})
            if 'lat' in condition and 'lon' in condition:
                lat = values['lat']
                lon = values['lon']
                # 纬度，经度
                lat_baidu, lon_baidu = coverGpsToBaiduLatLon(lat, lon)
                lat_d = convertDegreesToRadians(lat_baidu)
                _filter.filter_objects.append({
                    '$addFields': {
                        # 距离是以km单位的
                        "distance": {
                            '$multiply': [
                                {
                                    '$acos': {
                                        '$add': [
                                            {
                                                '$multiply': [
                                                    {
                                                        '$sin': {'$degreesToRadians': {"$toDouble": "$obj_list.organization_info.lat"}}
                                                    },
                                                    {
                                                        '$sin': lat_d
                                                    }
                                                ]
                                            },
                                            {
                                                '$multiply': [
                                                    {
                                                        '$cos': {'$degreesToRadians': {"$toDouble": "$obj_list.organization_info.lat"}}
                                                    },
                                                    {
                                                        '$cos': lat_d
                                                    },
                                                    {
                                                        '$cos': {
                                                            '$degreesToRadians': {
                                                                '$subtract': [
                                                                    {"$toDouble": "$obj_list.organization_info.lon"},
                                                                    lon_baidu
                                                                ]
                                                            }
                                                        }
                                                    }
                                                ]
                                            }
                                        ]
                                    }
                                },
                                # 地球平均半径
                                6371.004
                            ]
                        }
                    }
                })
            else:
                _filter.add_fields({'distance': None})
        if 'object' in condition.keys() and condition['object'] == FollowCollectionObject.news:
            _filter.lookup_bill('PT_Article', 'business_id', 'id', 'obj_list')\
                   .add_fields({'obj': self.ao.array_elemat("$obj_list", 0)})\
                   .lookup_bill('PT_User', 'obj.organization_id', 'id', 'org_list')\
                   .add_fields({'org': self.ao.array_elemat("$org_list", 0)})\
                .lookup_bill('PT_Service_Follow_Collection', 'obj.id', 'business_id', 'follow_info')\
                .add_fields({'follow_count': self.ao.size('$follow_info'), })\
                   .match_bill((C("obj_list.title").like(values["name"])))\
                   .project({"obj_list": 0, "org_list": 0, "org._id": 0, "follow_info._id": 0})
        if 'object' in condition.keys() and condition['object'] == FollowCollectionObject.activity:
            _filter.lookup_bill('PT_Activity', 'business_id', 'id', 'obj_list')\
                   .add_fields({'obj': self.ao.array_elemat("$obj_list", 0)})\
                   .lookup_bill('PT_Activity_Participate', 'obj.id', 'activity_id', 'participate')\
                   .add_fields({'participate_count': self.ao.size('$participate'), })\
                   .lookup_bill('PT_User', 'obj.organization_id', 'id', 'org_list')\
                   .add_fields({'org': self.ao.array_elemat("$org_list", 0)})\
                   .match_bill((C("obj_list.activity_name").like(values["name"])))\
                   .project({"obj_list": 0, "org._id": 0, "org_list": 0, 'participate': 0})
        if 'object' in condition.keys() and condition['object'] == FollowCollectionObject.service:
            _filter.lookup_bill('PT_Service_Product', 'business_id', 'id', 'obj_list')\
                   .add_fields({'obj': self.ao.array_elemat("$obj_list", 0)})\
                   .lookup_bill('PT_Service_Order', 'obj.id', 'detail.product_id', 'order_info')\
                   .add_fields({'pay_count': self.ao.size('$order_info'), 'total_price': '$service_package_price'})\
                   .lookup_bill('PT_User', 'obj.organization_id', 'id', 'org_list')\
                   .add_fields({'org': self.ao.array_elemat("$org_list", 0)})\
                   .match_bill((C("obj_list.name").like(values["name"])))\
                   .project({"obj_list": 0, "org._id": 0, "org_list": 0, 'order_info._id': 0})
        _filter.sort({'create_date': -1})\
            .project({"_id": 0, "user._id": 0, "obj._id": 0})
        res = self.page_query(
            _filter, "PT_Service_Follow_Collection", page, count)
        return res

    def update_service_follow_collection(self, business_id, s_type, s_object):
        """ 新增服务关注/收藏 data: ServiceFollowCollectionObject """
        res = 'Fail'
        user_id = get_current_user_id(self.session)
        dt = ServiceFollowCollectionObject(
            user_id, business_id, s_object, s_type)
        data = dt.to_dict()

        if 'id' in data.keys():
            bill_id = self.bill_manage_service.add_bill(OperationType.update.value,
                                                        TypeId.followCollection.value, data, 'PT_Service_Follow_Collection')
            if bill_id:
                res = 'Success'
        else:
            data_info = get_info(data, self.session)
            bill_id = self.bill_manage_service.add_bill(OperationType.add.value,
                                                        TypeId.followCollection.value, data_info, 'PT_Service_Follow_Collection')
            if bill_id:
                res = 'Success'
        if res == 'Success' and s_object == FollowCollectionObject.welfare and s_type == FollowCollectionType.follow:
            _filter = MongoBillFilter()
            _filter.match_bill((C('id') == business_id)).project({'_id': 0})
            res_product = self.query(
                _filter, 'PT_User')
            if len(res_product) > 0:
                real_account_data = OperationRecordObject(
                    get_current_user_id(self.session), OperationRecordType.follow_org, business_id, res_product[0]['name'])
                self.OperationRecordService.insert_record(
                    real_account_data.to_dict())
        return res

    def delete_service_follow_collection(self, follow_collection_ids):
        '''删除服务关注收藏

        Arguments:
            follow_collection_ids   {ids}      数据id
        '''
        res = 'Fail'

        def process_func(db):
            nonlocal res
            bill_id = self.bill_manage_service.add_bill(
                OperationType.delete.value, TypeId.followCollection.value, {'id': follow_collection_ids}, 'PT_Service_Follow_Collection')
            if bill_id:
                res = 'Success'
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def delete_service_follow_collection_by_business_id(self, condition):
        '''根据业务ID删除服务关注收藏
        '''

        keys = ["business_id", "object", "type"]
        values = self.get_value(condition, keys)

        _filter = MongoBillFilter()
        _filter.match_bill((C('business_id') == values['business_id']) & (C('object') == values['object']) & (C('type') == values['type']))\
            .project({'_id': 0})
        result = self.query(
            _filter, "PT_Service_Follow_Collection")

        res = 'Fail'

        if len(result) > 0:
            for item in result:
                bill_id = self.bill_manage_service.add_bill(
                    OperationType.delete.value, TypeId.followCollection.value, {'id': item['id']}, 'PT_Service_Follow_Collection')
                if bill_id:
                    res = 'Success'
        return res
